package com.ltcode.auth.application.service;

import com.ltcode.auth.domain.model.Captcha;
import com.ltcode.auth.domain.repository.CaptchaRepository;
import com.ltcode.common.base.exception.BizException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Optional;
import java.util.UUID;

/**
 * 验证码应用服务
 * 
 * @author ltcode
 * @since 2024-01-01
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CaptchaApplicationService {

    private final CaptchaRepository captchaRepository;
    private final CaptchaGeneratorService captchaGeneratorService;

    private static final int CAPTCHA_EXPIRE_MINUTES = 5; // 验证码5分钟过期

    /**
     * 生成字符验证码
     */
    public Captcha.CaptchaResult generateCharCaptcha() {
        log.debug("生成字符验证码");

        try {
            // 1. 生成验证码UUID
            String uuid = UUID.randomUUID().toString();

            // 2. 生成验证码内容和图片
            CaptchaGeneratorService.CaptchaData captchaData = captchaGeneratorService.generateCharCaptcha();

            // 3. 创建验证码对象
            Captcha captcha = Captcha.createCharCaptcha(
                    uuid, captchaData.getCode(), captchaData.getImage(), CAPTCHA_EXPIRE_MINUTES);

            // 4. 保存验证码
            captchaRepository.save(captcha);

            log.debug("生成字符验证码成功: uuid={}", uuid);
            return captcha.toResult();
        } catch (Exception e) {
            log.error("生成字符验证码失败", e);
            throw new RuntimeException("生成验证码失败", e);
        }
    }

    /**
     * 生成数学运算验证码
     */
    public Captcha.CaptchaResult generateMathCaptcha() {
        log.debug("生成数学运算验证码");

        try {
            // 1. 生成验证码UUID
            String uuid = UUID.randomUUID().toString();

            // 2. 生成验证码内容和图片
            CaptchaGeneratorService.CaptchaData captchaData = captchaGeneratorService.generateMathCaptcha();

            // 3. 创建验证码对象
            Captcha captcha = Captcha.createMathCaptcha(
                    uuid, captchaData.getCode(), captchaData.getImage(), CAPTCHA_EXPIRE_MINUTES);

            // 4. 保存验证码
            captchaRepository.save(captcha);

            log.debug("生成数学运算验证码成功: uuid={}", uuid);
            return captcha.toResult();
        } catch (Exception e) {
            log.error("生成数学运算验证码失败", e);
            throw new RuntimeException("生成验证码失败", e);
        }
    }

    /**
     * 验证验证码
     */
    public void validateCaptcha(String code, String uuid) {
        log.debug("验证验证码: uuid={}, code={}", uuid, code);


        try {
            // 1. 查询验证码
            Optional<Captcha> captchaOpt = captchaRepository.findByUuid(uuid);
            if (!captchaOpt.isPresent()) {
                throw new BizException("验证码不存在或已过期");
            }

            Captcha captcha = captchaOpt.get();

            // 2. 检查验证码是否有效
            if (!captcha.isValid()) {
                captchaRepository.deleteByUuid(uuid);
                if (captcha.isExpired()) {
                    throw new BizException("验证码已过期");
                } else if (captcha.isUsed()) {
                    throw new BizException("验证码已使用");
                } else if (captcha.isMaxFailCountReached()) {
                    throw new BizException("验证码错误次数过多");
                } else {
                    throw new BizException("验证码无效");
                }
            }

            // 3. 验证验证码
            boolean isValid = captcha.validate(code.trim());
            if (!isValid) {
                // 更新失败次数
                captchaRepository.save(captcha);
                
                if (captcha.isMaxFailCountReached()) {
                    captchaRepository.deleteByUuid(uuid);
                    throw new BizException("验证码错误次数过多，请重新获取");
                } else {
                    throw new BizException("验证码错误");
                }
            }

            // 4. 验证成功，删除验证码
            captchaRepository.deleteByUuid(uuid);

            log.debug("验证验证码成功: uuid={}", uuid);
        } catch (RuntimeException e) {
            log.warn("验证验证码失败: uuid={}, code={}, error={}", uuid, code, e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("验证验证码异常: uuid={}, code={}", uuid, code, e);
            throw new BizException("验证码验证失败", e);
        }
    }

    /**
     * 检查验证码是否存在
     */
    public boolean existsCaptcha(String uuid) {
        if (uuid == null || uuid.trim().isEmpty()) {
            return false;
        }

        try {
            return captchaRepository.existsByUuid(uuid);
        } catch (Exception e) {
            log.error("检查验证码是否存在失败: uuid={}", uuid, e);
            return false;
        }
    }

    /**
     * 删除验证码
     */
    public void deleteCaptcha(String uuid) {
        if (uuid == null || uuid.trim().isEmpty()) {
            return;
        }

        try {
            captchaRepository.deleteByUuid(uuid);
            log.debug("删除验证码成功: uuid={}", uuid);
        } catch (Exception e) {
            log.error("删除验证码失败: uuid={}", uuid, e);
        }
    }

    /**
     * 清理过期验证码
     */
    public void cleanExpiredCaptchas() {
        try {
            captchaRepository.cleanExpiredCaptchas();
            log.debug("清理过期验证码完成");
        } catch (Exception e) {
            log.error("清理过期验证码失败", e);
        }
    }
}
